package com.zouxw.utils.json.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
import com.github.fge.jsonschema.core.report.ProcessingReport;
import com.github.fge.jsonschema.main.JsonSchema;
import com.github.fge.jsonschema.main.JsonSchemaFactory;

import java.util.ArrayList;
import java.util.List;

/**
 * JSON Schema验证工具类
 * 提供JSON数据与Schema的验证功能
 * 
 * @author zouxw
 * @version 1.0.0
 */
public class JsonSchemaValidator {
    
    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final JsonSchemaFactory schemaFactory = JsonSchemaFactory.byDefault();
    
    /**
     * 验证结果类
     */
    public static class ValidationResult {
        private final boolean valid;
        private final List<String> errors;
        private final List<String> warnings;
        private final String summary;
        
        public ValidationResult(boolean valid, List<String> errors, List<String> warnings, String summary) {
            this.valid = valid;
            this.errors = errors != null ? errors : new ArrayList<>();
            this.warnings = warnings != null ? warnings : new ArrayList<>();
            this.summary = summary;
        }
        
        public boolean isValid() {
            return valid;
        }
        
        public List<String> getErrors() {
            return errors;
        }
        
        public List<String> getWarnings() {
            return warnings;
        }
        
        public String getSummary() {
            return summary;
        }
        
        public boolean hasErrors() {
            return !errors.isEmpty();
        }
        
        public boolean hasWarnings() {
            return !warnings.isEmpty();
        }
        
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("验证结果: ").append(valid ? "通过" : "失败").append("\n");
            sb.append("摘要: ").append(summary).append("\n");
            
            if (hasErrors()) {
                sb.append("错误信息:\n");
                for (String error : errors) {
                    sb.append("  - ").append(error).append("\n");
                }
            }
            
            if (hasWarnings()) {
                sb.append("警告信息:\n");
                for (String warning : warnings) {
                    sb.append("  - ").append(warning).append("\n");
                }
            }
            
            return sb.toString();
        }
    }
    
    /**
     * 验证JSON数据是否符合指定的Schema
     * 
     * @param jsonData JSON数据字符串
     * @param schemaString Schema字符串
     * @return 验证结果
     */
    public static ValidationResult validate(String jsonData, String schemaString) {
        try {
            // 解析JSON数据
            JsonNode jsonNode = objectMapper.readTree(jsonData);
            
            // 解析Schema
            JsonNode schemaNode = objectMapper.readTree(schemaString);
            JsonSchema schema = schemaFactory.getJsonSchema(schemaNode);
            
            // 执行验证
            ProcessingReport report = schema.validate(jsonNode);
            
            // 处理验证结果
            List<String> errors = new ArrayList<>();
            List<String> warnings = new ArrayList<>();
            
            report.forEach(message -> {
                String msg = message.getMessage();
                if (message.getLogLevel().name().equals("ERROR")) {
                    errors.add(msg);
                } else if (message.getLogLevel().name().equals("WARN")) {
                    warnings.add(msg);
                }
            });
            
            boolean isValid = report.isSuccess();
            String summary = isValid ? 
                "JSON数据完全符合Schema规范" : 
                String.format("发现 %d 个错误，%d 个警告", errors.size(), warnings.size());
            
            return new ValidationResult(isValid, errors, warnings, summary);
            
        } catch (Exception e) {
            List<String> errors = new ArrayList<>();
            errors.add("Schema验证过程中发生错误: " + e.getMessage());
            return new ValidationResult(false, errors, new ArrayList<>(), "验证失败");
        }
    }
    
    /**
     * 验证JSON数据是否符合指定的Schema（使用JSONObject）
     * 
     * @param jsonData JSON数据对象
     * @param schemaString Schema字符串
     * @return 验证结果
     */
    public static ValidationResult validate(JSONObject jsonData, String schemaString) {
        return validate(jsonData.toJSONString(), schemaString);
    }
    
    /**
     * 验证JSON数据是否符合指定的Schema（使用Object）
     * 
     * @param jsonData JSON数据对象
     * @param schemaString Schema字符串
     * @return 验证结果
     */
    public static ValidationResult validate(Object jsonData, String schemaString) {
        return validate(JSON.toJSONString(jsonData), schemaString);
    }
    
    /**
     * 检查Schema字符串是否有效
     * 
     * @param schemaString Schema字符串
     * @return 是否有效
     */
    public static boolean isValidSchema(String schemaString) {
        try {
            JsonNode schemaNode = objectMapper.readTree(schemaString);
            schemaFactory.getJsonSchema(schemaNode);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 获取Schema验证错误信息
     * 
     * @param schemaString Schema字符串
     * @return 错误信息，如果Schema有效则返回null
     */
    public static String getSchemaValidationError(String schemaString) {
        try {
            JsonNode schemaNode = objectMapper.readTree(schemaString);
            schemaFactory.getJsonSchema(schemaNode);
            return null;
        } catch (Exception e) {
            return "Schema格式错误: " + e.getMessage();
        }
    }
    
    /**
     * 创建简单的Schema验证器
     * 
     * @param schemaString Schema字符串
     * @return Schema验证器，如果Schema无效则返回null
     */
    public static JsonSchema createSchema(String schemaString) {
        try {
            JsonNode schemaNode = objectMapper.readTree(schemaString);
            return schemaFactory.getJsonSchema(schemaNode);
        } catch (Exception e) {
            return null;
        }
    }
    
    /**
     * 生成JSON数据的Schema（基础版本）
     * 
     * @param jsonData JSON数据字符串
     * @return 生成的Schema字符串
     */
    public static String generateSchema(String jsonData) {
        try {
            JsonNode jsonNode = objectMapper.readTree(jsonData);
            return generateSchemaFromNode(jsonNode).toString();
        } catch (Exception e) {
            return "{\"error\": \"无法生成Schema: " + e.getMessage() + "\"}";
        }
    }
    
    /**
     * 从JsonNode生成Schema
     * 
     * @param node JsonNode
     * @return 生成的Schema
     */
    private static JsonNode generateSchemaFromNode(JsonNode node) {
        ObjectMapper mapper = new ObjectMapper();
        
        if (node.isObject()) {
            // 对象类型
            JsonNode schema = mapper.createObjectNode();
            ((com.fasterxml.jackson.databind.node.ObjectNode) schema).put("type", "object");
            
            com.fasterxml.jackson.databind.node.ObjectNode properties = mapper.createObjectNode();
            node.fieldNames().forEachRemaining(fieldName -> {
                JsonNode fieldValue = node.get(fieldName);
                properties.set(fieldName, generateSchemaFromNode(fieldValue));
            });
            
            ((com.fasterxml.jackson.databind.node.ObjectNode) schema).set("properties", properties);
            return schema;
            
        } else if (node.isArray()) {
            // 数组类型
            JsonNode schema = mapper.createObjectNode();
            ((com.fasterxml.jackson.databind.node.ObjectNode) schema).put("type", "array");
            
            if (node.size() > 0) {
                // 使用第一个元素作为数组项的类型
                JsonNode itemSchema = generateSchemaFromNode(node.get(0));
                ((com.fasterxml.jackson.databind.node.ObjectNode) schema).set("items", itemSchema);
            }
            
            return schema;
            
        } else if (node.isTextual()) {
            // 字符串类型
            JsonNode schema = mapper.createObjectNode();
            ((com.fasterxml.jackson.databind.node.ObjectNode) schema).put("type", "string");
            return schema;
            
        } else if (node.isNumber()) {
            // 数字类型
            JsonNode schema = mapper.createObjectNode();
            if (node.isInt() || node.isLong()) {
                ((com.fasterxml.jackson.databind.node.ObjectNode) schema).put("type", "integer");
            } else {
                ((com.fasterxml.jackson.databind.node.ObjectNode) schema).put("type", "number");
            }
            return schema;
            
        } else if (node.isBoolean()) {
            // 布尔类型
            JsonNode schema = mapper.createObjectNode();
            ((com.fasterxml.jackson.databind.node.ObjectNode) schema).put("type", "boolean");
            return schema;
            
        } else if (node.isNull()) {
            // null类型
            JsonNode schema = mapper.createObjectNode();
            ((com.fasterxml.jackson.databind.node.ObjectNode) schema).put("type", "null");
            return schema;
            
        } else {
            // 未知类型
            JsonNode schema = mapper.createObjectNode();
            ((com.fasterxml.jackson.databind.node.ObjectNode) schema).put("type", "string");
            return schema;
        }
    }
    
    /**
     * 格式化Schema字符串
     * 
     * @param schemaString Schema字符串
     * @return 格式化后的Schema字符串
     */
    public static String formatSchema(String schemaString) {
        try {
            JsonNode schemaNode = objectMapper.readTree(schemaString);
            return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(schemaNode);
        } catch (Exception e) {
            return schemaString; // 如果格式化失败，返回原字符串
        }
    }
    
    /**
     * 压缩Schema字符串
     * 
     * @param schemaString Schema字符串
     * @return 压缩后的Schema字符串
     */
    public static String compressSchema(String schemaString) {
        try {
            JsonNode schemaNode = objectMapper.readTree(schemaString);
            return objectMapper.writeValueAsString(schemaNode);
        } catch (Exception e) {
            return schemaString; // 如果压缩失败，返回原字符串
        }
    }
}
